﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CsharpWpfManual
{
    /// <summary>
    /// PieChartControl.xaml 的交互逻辑
    /// </summary>
    public partial class PieChartControl : UserControl
    {

        public string Title { get; set; }
        public List<PiePart> PieParts { get; set; }

        public double Radius { get; set; }

        public PieChartControl()
        {
            InitializeComponent();
            lbTitle.Content = "2019年消费比列";
            piechart.Radius = 100;

            PieParts = new List<PiePart>()
            {
                new PiePart(){ PartName="吃饭", Percent=0.35,Fill=Brushes.Red},
                new PiePart(){ PartName="逛街", Percent=0.15,Fill=Brushes.Blue},
                new PiePart(){ PartName="买衣服", Percent=0.10,Fill=Brushes.Green},
                new PiePart(){ PartName="买车", Percent=0.40,Fill=Brushes.Gray},

            };
            

            lst.ItemsSource = PieParts;
        }

        private void root_Loaded(object sender, RoutedEventArgs e)
        {
            piechart.DrawPileChart(PieParts);
        }
    }

    public class PieChart : FrameworkElement
    {

        public List<DrawingVisual> LstChild = new List<DrawingVisual>();

        public double Radius { get; set; }

        public Point CenterPoint {
            get
            {
                return new Point(Radius + 20, Radius + 20);
            }
        }
        private int OffsetAngle;//第一块的初始偏移角度，默认正北为0


        private Point FirstPoint //相对起始点为 坐标0,radius   偏移OffsetAngle的点
        {
            get
            {
                return GetCirclePointFromPoint(new Point(0, -Radius), OffsetAngle,out Point txtp);
            }
        }

        public Point GetRealPoint(Point RelitivePoint)
        {
            var tmp = new Point(RelitivePoint.X + CenterPoint.X, RelitivePoint.Y + CenterPoint.Y);
            return tmp;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="currentPoint">当前的相对坐标</param>
        /// <param name="bs"></param>
        /// <param name="ane"></param>
        /// <returns>返回下一个起始相对坐标</returns>
        private Point DrawOneBlock(Point currentPoint, PiePart piePart)
        {
            DrawingVisual _drawingVisual = new DrawingVisual();
            this.AddVisualChild(_drawingVisual);
            LstChild.Add(_drawingVisual);

            PathGeometry pg = new PathGeometry();

            PathFigure pathFigure = new PathFigure() { IsClosed = true, IsFilled = true, StartPoint = CenterPoint };
            pathFigure.Segments.Add(new LineSegment(GetRealPoint(currentPoint), true));

            Point pointEnd = GetCirclePointFromPoint(currentPoint, piePart.Percent*360, out Point txtp);
            pathFigure.Segments.Add(new ArcSegment(GetRealPoint(pointEnd), new Size(Radius, Radius), 0, piePart.Percent*360 > 180 ? true : false, SweepDirection.Clockwise, true));
            pg.Figures.Add(pathFigure);
            var dc = _drawingVisual.RenderOpen();
            dc.DrawGeometry(piePart.Fill, new Pen(piePart.Fill, 3), pg);
            FormattedText formattedText = new FormattedText(
            string.Format("{0:P}", piePart.Percent),
            CultureInfo.GetCultureInfo("en-us"),
            FlowDirection.LeftToRight,
            new Typeface("Verdana"),
            10,
            Brushes.Black);
            dc.DrawText(formattedText, GetRealPoint(txtp));
            dc.Close();

            return pointEnd;
        }


        public PieChart()
        {


        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="PieParts"></param>
        /// <param name="pOffsetAngle">第一块的初始偏移角度，默认正北为0</param>
        public void DrawPileChart(List<PiePart> PieParts,int pOffsetAngle=0)
        {

            if(Radius <= 0)
            {
                return;
            }
            Point last= new Point();
            OffsetAngle = pOffsetAngle;

            foreach(var pie in PieParts)
            {
                if(PieParts.IndexOf(pie)==0)
                       last = DrawOneBlock(FirstPoint, pie);
                last = DrawOneBlock(last, pie);
            }
            
            

        }



        //必须重载这两个方法，不然是画不出来的
        // 重载自己的VisualTree的孩子的个数，由于只有一个DrawingVisual，返回1
        protected override int VisualChildrenCount
        {
            get { return LstChild.Count; }
        }

        // 重载当WPF框架向自己要孩子的时候，返回返回DrawingVisual
        protected override Visual GetVisualChild(int index)
        {
            return LstChild[index];

        }





        /// <summary>
        /// 获取圆周上相对与某点 旋转 指定角度的点坐标,    Matrix需要使用center是（0，0）的相对坐标
        /// </summary>
        /// <param name="angle">角度,从0到360度，以正北方向为0度，顺时针旋转角度增加</param>
        /// <returns>在圆周上旋转角度后的坐标</returns>
        public Point GetCirclePointFromPoint(Point StartPoint, double angle,out Point textPoint)
        {

            var textPointVector= new Vector(StartPoint.X/2, StartPoint.Y/2);
            var textPointMatrix = new Matrix();
            textPointMatrix.Rotate(angle/2);
            var textPointmp = (textPointVector * textPointMatrix);
            textPoint= textPointmp+ new Point(-20, 0);

            // 圆心平移到原点后0度所对应的向量
            var zeroAngleVector = new Vector(StartPoint.X, StartPoint.Y);

            // 旋转角度所对应的矩阵
            var rotateMatrix = new Matrix();
            rotateMatrix.Rotate(angle);

            var tmp = (zeroAngleVector * rotateMatrix);
            // 因旋转的中心点在原点,最后需要平移到实际坐标上

            return tmp + new Point(0, 0);
        }
    }


    public class PiePart
    {
        public string PartName { get; set; }
        public double Percent { get; set; }
        public Brush Fill { get; set; }

    }

}
